import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author Garima 
 *
 * Test cases for VendingMachine
 *
 */

public class VendingMachineTest {
	public VendingMachine myMachine;
	public VendingMachineItem item1;
	public VendingMachineItem item2;
	public VendingMachineItem item3;
	
	@Before
	public void setUp() throws Exception {
		myMachine = new VendingMachine();
		item1 = new VendingMachineItem ("Snickers", 1.25);
		item2 = new VendingMachineItem ("Cookies", 1.00);
	}

	@After
	public void tearDown() throws Exception {
	}
	
	/**
	 * Test vending machine item by checking if the item added on the slot is matched on slot A and B
	 * Also, test null items for slots with no items added on slot C and D since initially all slots are empty.
	 */
	@Test
	public void addItemTest1() {
		myMachine.addItem (item1, VendingMachine.A_CODE);
		myMachine.addItem (item2, VendingMachine.B_CODE);
		myMachine.addItem(item2, VendingMachine.D_CODE);
		assertSame(item1,myMachine.getItem(VendingMachine.A_CODE));
		assertSame(item2,myMachine.getItem(VendingMachine.B_CODE));
		assertNull(myMachine.getItem(VendingMachine.C_CODE));
		assertSame(item2, myMachine.getItem(VendingMachine.D_CODE));
	}

	/**
	 * Test vending machine to see if it allows to add different item on the same slot
	 * Expected error during test because of absence of throws VendingMachineException
	 */
	@Test(expected = VendingMachineException.class)
	public void addItemTest2() throws VendingMachineException{
		myMachine.addItem(item1, VendingMachine.B_CODE);
	}

	
	/**
	 * Test vending machine to see if it allows to add different item on the same slot
	 * throws VendingMachineException
	 */
	@Test(expected = VendingMachineException.class)
	public void addItemTest3() {
		myMachine.addItem(item2, VendingMachine.B_CODE);
	}

	/**
	 * Test vending machine to see if it allows to add on a slot with invalid code
	 * Expected to show error during test because of absence of throws VendingMachineException
	 */	
	@Test
	public void addItemTest4() throws VendingMachineException {
		myMachine.addItem(item2, VendingMachine.E_CODE);
	}

	/**
	 * Test vending machine to see if it allows to add on a slot with invalid code
	 * throws VendingMachineException
	 */	
	@Test(expected = VendingMachineException.class)
	public void addItemTest5() throws VendingMachineException{
		myMachine.addItem(item2, VendingMachine.E_CODE);
		assertNull(myMachine.getItem(VendingMachine.E_CODE));
	}

	/**
	 * Test vending machine to see if it allows to remove item from slot if code is invalid
	 * throws VendingMachineException
	 */	
	/*@Test(expected = VendingMachineException.class)
	public void removeItemTest3() throws VendingMachineException {
		myMachine.removeItem(VendingMachine.E_CODE);
	}*/
	
	/**
	 * Test vending machine to see if it allows to insert money
	 * Make sure the expected and the actual balance match
	 */
	@Test
	public void insertMoneyTest1() {
		myMachine.insertMoney(5.00);
		assertEquals(5.00, myMachine.getBalance(), 0.01);
	}

	/**
	 * Test vending machine to see if it adds up the two amount inserted correctly
	 * expected and actual total amount should match
	 */
	@Test
	public void insertMoneyTest4() {
		myMachine.insertMoney(3.00);
		myMachine.insertMoney(2.00);
		assertEquals(5.00, myMachine.getBalance(), 0.001);
	}

	/**
	 * Test vending machine to see if it gives the right balance
	 * Initialize balance, add item, purchase item, the expected & actual balance must match
	 */
	@Test
	public void getBalanceTest1() {
		myMachine.balance=5.00;
		myMachine.addItem(item1, VendingMachine.A_CODE);
		myMachine.makePurchase(VendingMachine.A_CODE);
		assertEquals(3.75, myMachine.getBalance(), 0.001);
	}

	/**
	 * Test vending machine to see if it allows to have negative balance
	 * Negative balance could mean insert more money in this scenario
	 */
	@Test
	public void getBalanceTest2() {
		myMachine.balance=0.50;
		myMachine.addItem(item2, VendingMachine.B_CODE);
		myMachine.makePurchase(VendingMachine.B_CODE);
		assertEquals(0.50, myMachine.getBalance(), 0.001);
	}	

	/**
	 * Test vending machine to see if it allows to purchase an item
	 * Return true if purchase is successful
	 */
	@Test
	public void makePurchaseTest1() {
		myMachine.balance=5.00;
		myMachine.addItem(item1, VendingMachine.A_CODE);
		assertTrue(myMachine.makePurchase(VendingMachine.A_CODE));
	}

	/**
	 * Test vending machine to see if it allows to purchase an item when balance is low
	 * Return false if purchase is not allowed
	 */
	@Test
	public void makePurchaseTest2() {
		myMachine.balance=1.00;
		myMachine.addItem(item1, VendingMachine.A_CODE);
		assertFalse(myMachine.makePurchase(VendingMachine.A_CODE));
	}

	/**
	 * Test vending machine to see if it allows to purchase an item from empty slot
	 * Return false if purchase is unsuccessful
	 */
	@Test
	public void makePurchaseTest3() {
		myMachine.balance=5.00;
		assertFalse(myMachine.makePurchase(VendingMachine.C_CODE));
	}

	/**
	 * Test vending machine to see if it allows to purchase an item from slot with invalid code
	 * Return false if purchase is unsuccessful
	 */
	/*@Test
	public void makePurchaseTest4() {
		myMachine.balance=5.00;
		assertFalse(myMachine.makePurchase(VendingMachine.E_CODE));
	}*/

	/**
	 * Test vending machine to see if it return change after purchase
	 * Expected and actual change should match
	 */
	@Test
	public void returnChangeTest1() {
		myMachine.insertMoney(2.00);
		myMachine.addItem(item1, VendingMachine.A_CODE);
		myMachine.makePurchase(VendingMachine.A_CODE);
		assertEquals (0.75, myMachine.returnChange(), 0.01);
	}
	

}
